`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    18:07:44 05/28/2013 
// Design Name: 
// Module Name:    BoardConfiguration 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
/* This configuration:
    MMIO0 = Leds
    MMIO1 = Switches
    MMIO2 = Hex7Segs
    MMIO3 = PS2Keyboard
    MMIO4 = Servo
    MMIO5 = HexKeypad
    MMIO6 = StepperMotor
    MMIO7 = StaticOscillator
*/
module BoardConfiguration(
    input clk_50,
    output [7:0] leds,
    input [7:0] switches,
    input [3:0] pButtons,
    output [6:0] segDisplaySegs,
    output segDisplayDot,
    output [3:0] segDisplaySelector,
    inout [7:0] JA,
    inout [7:0] JB,
    inout [7:0] JC,
    input EppAstb,
    input EppDstb,
    input EppWR,
    output EppWait,
    inout [7:0] EppDB,
    inout PS2D,
    inout PS2C
    );
	
	wire [83:72] PIO; //board PMOD ports
	
	//board Specific Remap;
	assign JA = PIO[79:72];
	//assign JB[3:0] = PIO[83:80];
	//assign JB[7:4] = 4'b0;
	
	//clock wires
	wire clk_25;
	wire clk_12p5;
	
	ClockDivider clkDiv_25(clk_50, clk_25);
	ClockDivider clkDiv_12p5(clk_25, clk_12p5);
	
	wire mclk;
	assign mclk = clk_50;
	
	//reset wires
	wire reset = pButtons[0];
	wire CPU_Master_Reset;
	    
	//instatiation of Board Interface
	wire [1:0] mode;
	wire [0:0] debug_cpu_clks;
	wire [3:0] memorySelector;
	wire [31:0] BI_MemorySize;
	wire [31:0] BI_MEM_Address;
	wire [31:0] BI_Mem_Out;
	wire BI_Mem_Done;
	wire [31:0] BI_Mem_DataIn;
	wire BI_MEM_Write;
	wire [3:0] cpuSelector;
	wire [7:0] cpuFrequency;
	wire [31:0] cpuPC;
	wire [4:0] cpuRegisterSelector;
	wire [31:0] cpuRegisterValue;
	
	BoardInterface #(1, 1) BoardInterfaceInstance(clk_50, reset,
	mode, pButtons[1],
	debug_cpu_clks,
	EppAstb, EppDstb, EppWR, EppWait, EppDB, //EPP wires
	memorySelector, BI_MemorySize, BI_MEM_Address, BI_Mem_Out, BI_Mem_Done, BI_Mem_DataIn, BI_MEM_Write,
	cpuSelector, cpuFrequency, cpuPC, cpuRegisterSelector, cpuRegisterValue);
	
	
	//instatiation of SevenSeg Hardware Basic
	reg [3:0] sevenSegEnables;
	reg [15:0] sevenSegData;
	reg [3:0] sevenSegDots;
	SevenSeg debuggerSeg(clk_50,
	 sevenSegEnables,
    sevenSegData[3:0],
    sevenSegData[7:4],
    sevenSegData[11:8],
	 sevenSegData[15:12],
	 sevenSegDots,
	 segDisplaySegs,
	 segDisplayDot,
	 segDisplaySelector
    );
	//other wire defs
	parameter MODE_PC_DOWNLOADER = 2'b00;
	parameter MODE_UNKNOWN = 2'b01;
	parameter MODE_DEBUG = 2'b10;
	parameter MODE_RUN = 2'b11;
	

	assign CPU_Master_Reset = (mode == MODE_PC_DOWNLOADER);
	
	wire clk_cpu0 = clk_25;
	wire CPU_0_Reset = pButtons[0];
	

	//MEM_HEADER_WIRES
	
	/////// MEMORY 1 ////////
	
	wire [31:0] MEM1_Address1;
	wire [31:0] MEM1_DataOut1;
	wire [31:0] MEM1_DataIn1;
	wire MEM1_Write1;
	wire MEM1_Ack1 = 1;
	wire [31:0] MEM1_Address2;
	wire [31:0] MEM1_DataOut2;
	wire [31:0] MEM1_DataIn2;
	wire MEM1_Write2 = 0;
	wire MEM1_Ack2 = 1;
	wire MEM1_Address1_Invalid = |MEM1_Address1[31:10];
	wire MEM1_Address2_Invalid = |MEM1_Address2[31:10];
	
	
	DISMEM32w256d simpleMemory (
  MEM1_Address1[9:2], // input [7 : 0] a
  MEM1_DataIn1, // input [31 : 0] d
  MEM1_Address2[9:2], // input [7 : 0] dpra
  mclk, // input clk
  MEM1_Write1, // input we
  MEM1_DataOut1, // output [31 : 0] spo
  MEM1_DataOut2 // output [31 : 0] dpo
);

	//this is a memory output selector for the Board Interface Module
	reg BI_Mem_DoneReg;
	 reg [31:0] BI_Mem_OutReg;
	 assign BI_Mem_Done = BI_Mem_DoneReg;
	 assign BI_Mem_Out = BI_Mem_OutReg;
	 always @(*) begin
		case(memorySelector)
			4'd0: begin
				BI_Mem_OutReg = MEM1_DataOut1;
				BI_Mem_DoneReg = MEM1_Ack1;
			end
			default: begin
				BI_Mem_OutReg = 32'b0;
				BI_Mem_DoneReg = 1;
			end
		endcase
	 end
	
	//Controller Definitions
	
	// noc - number of controllers
	localparam noc = 6;
	
	wire			c_enable		[ noc - 1 : 0 ];
	wire  [3:0] c_address	[ noc - 1 : 0 ];
	wire [31:0] c_dataIn		[ noc - 1 : 0 ];
	wire [31:0] c_dataOut	[ noc - 1 : 0 ];
	wire        c_write		[ noc - 1 : 0 ];
	wire        c_done		[ noc - 1 : 0 ];
	wire       [ noc - 1 : 0 ] c_interrupt;
	
	//wire [ noc - 1 : 0 ] c_io_bus [1 + 4 + 32 + 32 + 1 + 1 + 1 - 1 : 0];
	wire  [(1 + 4 + 32 + 32 + 1 + 1 + 1) - 1 : 0] c_io_bus [ noc - 1 : 0 ];
	genvar c_std_io_i;
	generate
	for( c_std_io_i = 0 ; c_std_io_i < noc ; c_std_io_i = c_std_io_i + 1 )
	begin:controller_io_bus_assign 
		assign c_io_bus[c_std_io_i] = {mclk , reset , c_enable[c_std_io_i] , c_address[c_std_io_i][3:0] , c_dataIn[c_std_io_i][31:0] , c_dataOut[c_std_io_i][31:0] , c_write[c_std_io_i] , c_done[c_std_io_i] , c_interrupt[c_std_io_i]};
	end
	endgenerate
	
	//wire io = {mclk , reset , c_enable[0] , c_dataIn[0] , c_dataOut[0] , c_write[0] , c_done[0] , c_interrupt[0]};
	
	//On-Board Led Controller
	//OnBoardLedController OBLC_Instance(c_io_bus[0][4+32+32+3],c_io_bus[0][3+32+32+3:32+32+3],c_io_bus[0][31+32+3:32+3],c_io_bus[0][31+3:3],c_io_bus[0][2],c_io_bus[0][1],c_io_bus[0][0],leds);
	 //mclk , reset , c_enable , c_dataIn , c_dataOut , c_write , c_done , c_interrupt
	 
	//On-Board Switches Controller
	OnBoardSwitchesController OBSWC_Instance(c_io_bus[1], switches);
	
	//On-Board 7 Seg Hex Controller
	wire  [3:0] OBSSC_digitEnables;
	wire [15:0] OBSSC_data;
	wire  [3:0] OBSSC_dots;
	OnBoard7SegHexController OBSS_Instance(c_io_bus[2], OBSSC_digitEnables, {OBSSC_dots, OBSSC_data});
	
	//PmodCON3Controller OFBSERC_Instance(mclk, reset, OFBSERc_enable, OFBSERc_address, OFBSERc_dataIn, OFBSERc_dataOut, OFBSERc_write, OFBSERc_done, OFBSERc_interrupt, clk_50, PIO[83:80]); 
	
	PS2KeyboardController OBKBC_Instance(c_io_bus[3], clk_50, PS2C, PS2D);
	
	// External Hex Keypad Controller (attached to JC)
	HexKeypadController EHK_Instance(c_io_bus[4], JC);

	timer14 timer_instance( c_io_bus[5] );

	// External Stepper Motor Controller (attached to JA)
	//StepperMotorController ESM_Instance(mclk, reset, ESM_Enable, ESM_Address, ESM_DataIn, ESM_DataOut, ESM_Write, ESM_Done, ESM_Interrupt, JB);
	
	// External IS2 Static Oscillator Controller (attached to JB[3:0])
	//StaticOscillatorController I2SSO_Instance(mclk, reset, I2SSO_Enable, I2SSO_Address, I2SSO_DataIn, I2SSO_DataOut, I2SSO_Write, I2SSO_Done, I2SSO_Interrupt, JB[7:4]);

	///***************** SYSTEM DEFINITIONS ******************* ///
	
	/// ###################### SYS1 ########################### ///
	
	//SYSTEM 1 Bus Wire Definitions
	wire [31:0] SYS1_InstructionBus_Address;
	wire [31:0] SYS1_InstructionBus_Data;
	wire SYS1_InstructionBus_InvalidAddress = MEM1_Address2_Invalid;
	wire SYS1_InstructionBus_Ack;
	wire [31:0] SYS1_DataBus_Address;
	wire [31:0] SYS1_DataBus_DataFromCPU;
	wire [31:0] SYS1_DataBus_DataToCPU;
	wire SYS1_DataBus_InvalidAddress;
	wire SYS1_DataBus_Write;
	
	wire SYS1_DataBus_Ack;
	
	wire [15:0] SYS1_IOEnables;
	wire [15:0] SYS1_Interrupts;
	
	wire SYS1_DataBus_MMIO = &SYS1_DataBus_Address[31:16];
	
	wire cpu0_clk;
	wire cpu0_reset;
	
	//START SYSTEM 1 LOGIC
	wire SYS1_DataBus_Read;
	 
	
	 //ignored always reading unless writing
	
	/*BusStimulator myStimulator(clk_cpu0,
	CPU_0_Reset | CPU_Master_Reset,
	SYS1_InstructionBus_Address,
	SYS1_InstructionBus_Data,
	SYS1_InstructionBus_Ack,
	SYS1_DataBus_Write,
	SYS1_DataBus_Read,
	SYS1_DataBus_Ack,
	SYS1_DataBus_Address,
	SYS1_DataBus_DataFromCPU,
	SYS1_DataBus_DataToCPU,
	SYS1_Interrupts,
	//extras not required for real cpu instance
	pButtons[1],
	pButtons[2],
	,
	{dots, sevenSegData}
	);*/
	
	reg [31:0] MEM1_Address1Reg;
	reg [31:0] MEM1_DataIn1Reg;
	reg MEM1_Write1Reg;
	reg cpu0_clkReg;
	assign MEM1_Address1 = MEM1_Address1Reg;
	assign MEM1_DataIn1 = MEM1_DataIn1Reg;
	assign MEM1_Write1 = MEM1_Write1Reg;
	assign cpu0_clk = cpu0_clkReg;
	
	always @(*) begin
		case (mode)
			MODE_PC_DOWNLOADER: begin
				MEM1_Address1Reg <= (memorySelector == 4'b0) ? BI_MEM_Address : 32'b0;
				MEM1_DataIn1Reg <= (memorySelector == 4'b0) ? BI_Mem_DataIn : 32'b0;
				MEM1_Write1Reg <= (memorySelector == 4'b0) ? BI_MEM_Write : 0;
				cpu0_clkReg <= 0;
			end
			MODE_UNKNOWN: begin
				MEM1_Address1Reg <= {22'b0, switches, 2'b0};
				MEM1_DataIn1Reg <= 32'b0;
				MEM1_Write1Reg <= 0;
				cpu0_clkReg <= 0;
			end
			MODE_DEBUG: begin
				MEM1_Address1Reg <= (SYS1_DataBus_MMIO ? 32'b0 : SYS1_DataBus_Address);
				MEM1_DataIn1Reg <= SYS1_DataBus_DataFromCPU;
				MEM1_Write1Reg <= ~SYS1_DataBus_MMIO & SYS1_DataBus_Write;
				cpu0_clkReg <= debug_cpu_clks[0];
			end
			MODE_RUN: begin
				MEM1_Address1Reg <= (SYS1_DataBus_MMIO ? 32'b0 : SYS1_DataBus_Address);
				MEM1_DataIn1Reg <= SYS1_DataBus_DataFromCPU;
				MEM1_Write1Reg <= ~SYS1_DataBus_MMIO & SYS1_DataBus_Write;
				cpu0_clkReg <= clk_12p5; //setting the default run speed of cpu 0 to 25mhz
			end
		endcase
	end
	
	assign MEM1_Address2 = SYS1_InstructionBus_Address;
	assign SYS1_InstructionBus_Data = MEM1_DataOut2;
	assign SYS1_InstructionBus_Ack = MEM1_Ack2;
	
	mips cpu_instance(cpu0_clk,
	CPU_0_Reset | CPU_Master_Reset,
	SYS1_InstructionBus_Address,
	SYS1_InstructionBus_Data,
	SYS1_InstructionBus_Ack,
   SYS1_InstructionBus_InvalidAddress, // InstrInvalidAddressF
	SYS1_DataBus_Write,
	SYS1_DataBus_Read,
	SYS1_DataBus_Ack,
   SYS1_DataBus_InvalidAddress, // DataInvalidAddressM
	SYS1_DataBus_Address,
	SYS1_DataBus_DataFromCPU,
	SYS1_DataBus_DataToCPU,
	SYS1_Interrupts,
	cpuRegisterSelector,
	cpuRegisterValue
	);
	

	 wire [7:0]segData = ~pButtons[1] ? SYS1_InstructionBus_Address[7:0] : SYS1_InstructionBus_Data[7:0];
	 
	 PmodSSD debugger2(clk_50, segData[7:4],
    segData[3:0], PIO[78:72], PIO[79]);
	
	IRQDecoder SYS1EnableMux(SYS1_DataBus_MMIO, SYS1_DataBus_Address[9:6], SYS1_IOEnables);
	
	//Assigning all Memory Mapped IO Wires
	genvar mmio_i;
	generate
	for( mmio_i = 0 ; mmio_i < noc ; mmio_i = mmio_i + 1 )
	begin:peripheral_mmio_assign
		assign c_dataIn[mmio_i] = SYS1_DataBus_DataFromCPU;
		assign c_enable[mmio_i]  = SYS1_IOEnables[mmio_i];
		assign c_address[mmio_i] = SYS1_DataBus_Address[5:2];
		assign c_write[mmio_i]   = SYS1_DataBus_Write;
	end
	endgenerate
	
	//16 bit interrupt bus assignment
	//assign SYS1_Interrupts = {8'b0, I2SSO_Interrupt, ESM_Interrupt, EHK_Interrupt, OFBSERc_interrupt, OBKBc_interrupt, OBSSc_interrupt, OBSWc_interrupt, OBLc_interrupt};
	//assign SYS1_Interrupts = { {(16-noc){1'b0}} , { c_interrupt } };
	assign SYS1_Interrupts = c_interrupt;
	
	//Controller & memory to data bus selector
	reg [31:0] S1_DBD;

	integer sys_db_a;
	reg S1_DBDone;
	reg SYS1_DataBus_InvalidAddress_reg;
	//always @ (*) begin 
	always @ (posedge mclk) begin 
	//always @ ( SYS1_DataBus_Address[9:6] , [noc-1:0]c_dataOut , c_done , MEM1_DataOut1 , MEM1_Ack1 , MEM1_Address2_Invalid ) begin // ??? xxx bug wrong.
		if(SYS1_DataBus_MMIO)
		begin
			sys_db_a <= SYS1_DataBus_Address[9:6];
			
			if( sys_db_a < noc )
			begin
				S1_DBD <= c_dataOut[sys_db_a];
				S1_DBDone <= c_done[sys_db_a];
				SYS1_DataBus_InvalidAddress_reg <= 1'b0;
			end
			else
			begin
				S1_DBD <= 32'b0;
				S1_DBDone <= 1'b1;
				SYS1_DataBus_InvalidAddress_reg <= 1'b1;
			end
			
		end
		else
		begin
			S1_DBD <= MEM1_DataOut1;
			S1_DBDone <= MEM1_Ack1;
			SYS1_DataBus_InvalidAddress_reg <= MEM1_Address2_Invalid;
		end
	end
	
	assign SYS1_DataBus_DataToCPU = S1_DBD;
	assign SYS1_DataBus_Ack = S1_DBDone;
	assign SYS1_DataBus_InvalidAddress = SYS1_DataBus_InvalidAddress_reg;
	
	//END SYSTEM 1 Logic
	
	parameter CON_CPU_NUM = 1;
	parameter CON_MEM_NUM = 1;
	 
	parameter CPU_NUM = 4'd1;
	parameter MEM_NUM = 4'd1;
	 
	 // CPU FREQUENCY CONSTANTS ROM
	 
	 reg [7:0] cpu_frequency;
	 reg [31:0] cpu_PCReg;
	 assign cpuFrequency = cpu_frequency;
	 assign cpuPC = cpu_PCReg;
	 always @(*) begin
		case(cpuSelector)
			4'd0: begin
				cpu_frequency = 8'd1;
				cpu_PCReg = SYS1_InstructionBus_Address;
				end				
			default: begin
				cpu_frequency = 8'd0;
				cpu_PCReg = 32'b0;
				end
		endcase
	 end
	
	// Memory Size CONSTANTS ROM
	 
	 reg [31:0] mem_size;
	 assign BI_MemorySize = mem_size;
	 always @(*) begin
		case(memorySelector)
			4'd0: mem_size = 32'd256;
			default: mem_size = 32'd0;
		endcase
	 end
	 
	wire [15:0] databw = ~pButtons[3] ? SYS1_DataBus_DataFromCPU[15:0] : SYS1_DataBus_DataFromCPU[31:16];
	wire [15:0] databr = ~pButtons[3] ? SYS1_DataBus_DataToCPU[15:0] : SYS1_DataBus_DataToCPU[31:16];
	wire [15:0] datab = SYS1_DataBus_Write ? databw : databr;
	
	//shows data adress normally
	//pressing btn3 shows up half of data
	//pressing btn1 shows data
	 
	 //7Seg switcher for debugger
	always @(*) begin
		if(mode[1]) begin// if in debugger or run mode
			sevenSegEnables = OBSSC_digitEnables; //(mode[0]) ? OBSSC_digitEnables : 4'b1111;
			sevenSegData = OBSSC_data;//(mode[0]) ? OBSSC_data : (~(pButtons[1]) ? (~pButtons[3] ? SYS1_DataBus_Address[15:0] : SYS1_DataBus_Address[31:16]) : datab);
			sevenSegDots[3:2] = OBSSC_dots[3:2]; //(mode[0]) ? OBSSC_dots[3:2] : {SYS1_DataBus_Write, SYS1_DataBus_MMIO};
         sevenSegDots[1:0] = mode;//OBSSC_dots[1:0];
		end
		else begin
			sevenSegEnables = ~(mode[0]) ? 4'd0 : 4'b1111;
			sevenSegData = (~pButtons[3] ? MEM1_DataOut1[15:0] : MEM1_DataOut1[31:16]);
			sevenSegDots[3:2] = 2'b0;
			sevenSegDots[1:0] = mode;
		end
		
	end

endmodule
